package agh.rozproszony.reservations;

import View.InvitationRow;
import agh.rozproszony.DBStorage.DataBaseEngine;
import agh.rozproszony.model.Invitation;
import agh.rozproszony.model.Reservation;
import agh.rozproszony.model.Room;
import agh.rozproszony.model.User;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ReservationsRMIServer extends UnicastRemoteObject implements ReservationsServer {

    protected DataBaseEngine db;
    protected List<ReservationEventListener> listeners = new ArrayList<ReservationEventListener>();

    public ReservationsRMIServer(DataBaseEngine db) throws RemoteException {
        this.db = db;
    }

    @Override
    public List<Room> getAllRooms() throws RemoteException {
        try {
            System.out.println("SERWER: Zwracanie wszsytkich pokoi do klienta");
            return db.getAllRooms();
        } catch (SQLException ex) {
            throw new RemoteException("SERWER: Nie mozna pobrac pokoi z bazy danych", ex);
        }
    }

    @Override
    public List<User> getAllUsers() throws RemoteException {
        try {
            System.out.println("SERWER: Zwracanie wszsytkich uzytkownikow do klienta");
            return db.getAllUsers();
        } catch (SQLException ex) {
            throw new RemoteException("SERWER: Nie mozna pobrac uzytkownikow z bazy danych", ex);
        }
    }

    @Override
    public List<Reservation> getAllReservations() throws RemoteException {
        try {
            System.out.println("SERWER: Zwracanie wszsytkich rezerwacji do klienta");
            return db.getAllReservations();
        } catch (SQLException ex) {
            throw new RemoteException("SERWER: Nie mozna pobrac rezerwacji z bazy danych", ex);
        }
    }

    @Override
    public synchronized boolean addReservation(Reservation reservation) throws RemoteException {
        try {
            System.out.println("SERWER: Sprawdzanie mozliwosci rezerwacji");
            if (!db.isReservationPossible(reservation)) {
                return false;
            }
            System.out.println("SERWER: Dodawanie rezerwacji");
            db.insertReservation(reservation);
            return true;
        } catch (SQLException ex) {
            throw new RemoteException("SERWER: Nie mozna dodac rezerwacji do bazy danych", ex);
        }
    }

    @Override
    public boolean validateLoginPasswordUser(String login, char[] password) throws RemoteException {
        try {
            List<User> allUsers = db.getAllUsers();
            String pass = new String(password);
            for (User user : allUsers) {
                if (user.getLogin().equals(login) && user.getPassword().equals(pass)) {
                    return true;
                }
            }
            return false;

        } catch (SQLException ex) {
            Logger.getLogger(ReservationsRMIServer.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
    }

    @Override
    public User getUserByLogin(String login) throws RemoteException {
        try {
            return db.getUserByLogin(login);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna pobrac uzytkownika po loginie z bazy danych", ex);
        }
    }

    @Override
    public void addInvitation(Invitation invitation) throws RemoteException {
        try {
            if (db.getReservation(invitation.getReservationId()) == null) {
                throw new RemoteException("Nie znaleziono w bazie danych rezerwacji dla dodawanego zaproszenia");
            }
            if (db.getUser(invitation.getUserId()) == null) {
                throw new RemoteException("Nie znaleziono w bazie danych uzytkownika dla dodawanego zaproszenia");
            }

            db.insertInvitiation(invitation);

            // Powiadomienie wszsytkich obserwatorow, ze w systmie pojawilo sie nowe zaproszenie
            for (ReservationEventListener listener : listeners) {
                if (listener.getLoggedUserId() == invitation.getUserId()) {
                    listener.newInvitationArrived();
                }
            }

            // TODO: wyslac wiadomosc do zaproszonego uzytkownika, ze czeka na niego nowe zaproszenie
        } catch (SQLException ex) {
            throw new RemoteException("SERWER: Nie mozna dodac zaproszenia", ex);
        }
    }

    @Override
    public void addReservationEventListener(ReservationEventListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeReservationEventListener(ReservationEventListener listener) {
        listeners.remove(listener);
    }

    @Override
    public List<Invitation> getAwaitingInvitations(int userId) throws RemoteException {
        try {
            return db.getAwaitingInvitations(userId);
        } catch (SQLException ex) {
            throw new RemoteException("SERWER: Nie mozna pobrac z bazy listy niezaakceptowanych zaproszen", ex);
        }
    }

    @Override
    public User getUserByEmail(String email) throws RemoteException, SQLException {
        return db.getUserByEmail(email);
    }

    @Override
    public String getReservationRoomName(int id) throws RemoteException, SQLException {
        return db.getReservationRoomName(id);
    }

    @Override
    public String getReservationOwnerLogin(int id) throws RemoteException, SQLException {
        return db.getReservationOwnerLogin(id);
    }

    @Override
    public List<Reservation> getAllReservations(Date from, Date to) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public List<Reservation> getAllReservations(Date from, Date to, int roomId) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void deleteUser(User user) throws RemoteException {
        try {
            db.deleteUser(user);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna dodac pokoju do bazy danych", ex);
        }
    }

    @Override
    public void deleteReservation(Reservation reservation) throws RemoteException {
        try {
            db.deleteReservation(reservation);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna dodac pokoju do bazy danych", ex);
        }
    }

    @Override
    public void insertUser(User user) throws RemoteException {
        try {
            db.insertUser(user);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna dodac uzytkownika do bazy danych", ex);
        }
    }

    @Override
    public void insertRoom(Room room) throws RemoteException {
        try {
            db.insertRoom(room);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna dodac pokoju do bazy danych", ex);
        }
    }

    @Override
    public void deleteRoom(Room room) throws RemoteException {
        try {
            db.deleteRoom(room);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna dodac pokoju do bazy danych", ex);
        }
    }

    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    @Override
    public int getReservationId(Reservation reservation) throws RemoteException {
        try {
            return db.getReservationId(reservation);
        } catch (SQLException ex) {
            Logger.getLogger(ReservationsRMIServer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return 0;
    }

    @Override
    public Reservation getReservation(int id) throws RemoteException {
        try {
            return db.getReservation(id);
        } catch (SQLException ex) {
            Logger.getLogger(ReservationsRMIServer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    @Override
    public User getUserNameById(int id) {
        try {
            return db.getUser(id);
        } catch (SQLException ex) {
            Logger.getLogger(ReservationsRMIServer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }

    @Override
    public int deleteInvitation(InvitationRow removeUnselectedRows) throws RemoteException {
        try {
            return db.deleteInvitation(removeUnselectedRows);
        } catch (SQLException ex) {
            Logger.getLogger(ReservationsRMIServer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return 1;

    }

    @Override
    public void setInvitationAccepted(int userId, int reservationId) throws RemoteException {
        try {
            db.setInvitationAccepted(userId, reservationId);
        } catch (SQLException ex) {
            throw new RemoteException("Nie mozna ustawic zaproszenia jako zaakceptowane", ex);
        }
    }
}
